// main.js
import { exec } from 'child_process'
import dayjs from 'dayjs'
import {
  app,
  BrowserWindow,
  dialog,
  globalShortcut,
  ipcMain,
  Menu,
  protocol,
  screen,
  systemPreferences,
} from 'electron'
import Store from 'electron-store'
import fs from 'fs'
import path from 'path'
import { ping } from 'qiao-ping'
import si from 'systeminformation'

if (!app.requestSingleInstanceLock()) {
  app.quit()
  process.exit(0)
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
let win: any = null
// 创建窗口
const createWindow = () => {
  const { width, height } = screen.getPrimaryDisplay().workAreaSize
  // Create the browser window.
  win = new BrowserWindow({
    icon: path.join(__dirname, '../public/app.ico'),
    frame: true,
    webPreferences: {
      preload: path.join(__dirname, '../electron/preload.js'),
    },
    // fullscreen: true, // 默认全屏
    // resizable: false, // 禁止窗口缩放
    width, // 设置初始化大小
    height, // 设置初始化大小
    show: true,
    minWidth: 1400, // 设置窗口的最小宽度
    minHeight: 860, // 设置窗口的最小高度
  })

  // 加载 index.html
  win.loadURL(
    process.env.VITE_DEV_SERVER_URL
      ? process.env.VITE_DEV_SERVER_URL
      : `file://${path.join(__dirname, '../dist-html/index.html')}`
  )
  // win.setContentProtection(true)
}

// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {
  // 注册自定义协议
  protocol.registerFileProtocol('custom', (request, callback) => {
    const url = request.url.slice('custom://'.length) // 去掉协议头 'custom://'
    const path = decodeURIComponent(url) // 解码 URL
    return callback(path)
  })
  createWindow()
  globalShortcut.register('CommandOrControl+Shift+i', () => {
    win.webContents.openDevTools() //开启开发者工具
  })

  if (process.env.VITE_DEV_SERVER_URL) {
    win.webContents.openDevTools()
  } else {
    // win.webContents.openDevTools()
    Menu.setApplicationMenu(Menu.buildFromTemplate([]))
  }

  /**
   * 当应用被激活时发出
   */
  app.on('activate', () => {
    // 在 macOS 系统内, 如果没有已开启的应用窗口
    // 点击托盘图标时通常会重新创建一个新窗口
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow()
    }
  })

  win.on('close', (event) => {
    // 取消默认的窗口关闭行为，这样应用程序不会立即退出
    event.preventDefault()
    win.webContents.send('close')
  })
  ipcMain.on('confirmClose', () => {
    if (win) {
      win.destroy()
      app.quit()
    }
  })
})

app.on('second-instance', () => {
  if (win) {
    if (win.isMinimized()) win.restore()
    win.focus()
  }
})

// 除了 macOS 外，当所有窗口都被关闭的时候退出程序。 因此, 通常
// 对应用程序和它们的菜单栏来说应该时刻保持激活状态,
// 直到用户使用 Cmd + Q 明确退出
/**
 * 当所有的窗口都被关闭时触发。
 */
app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

/**
 * 窗口被关闭后
 */
app.on('will-quit', () => {
  // 注销所有快捷键
  globalShortcut.unregisterAll()
})

// 在当前文件中你可以引入所有的主进程代码
// 也可以拆分成几个文件，然后用 require 导入。
// 定义ipcRenderer监听事件

const configPath = path.join(app.getPath('userData'))
console.log(app.getPath('userData'))
ipcMain.handle('fsPermissions', async (_) => {
  //采用qiao-is-online判断当前网络
  return new Promise((resolve) => {
    fs.access(configPath, fs.constants.W_OK, (err) => {
      if (err) {
        console.log(`${configPath} 目录不存在或者没有写入权限`)
        resolve(`${configPath} 目录不存在或者没有写入权限`)
      }
      // 在此处进行文件操作
      console.log(app.getPath('userData'), `拥有写入读取权限`)
      resolve(`${configPath} 拥有写入读取权限`)
    })
  })
})

// 检查目录是否存在，如果不存在则创建
/**store*/
const option = {
  name: 'config', //文件名称,默认 config
  fileExtension: 'json', //文件后缀,默认json
  cwd: configPath, //文件位置,尽量不要动，默认情况下，它将通过遵循系统约定来选择最佳位置。C:\Users\xxx\AppData\Roaming\test\config.json
  encryptionKey: 'aes-256-cbc', //对配置文件进行加密
  //getoutrightnow 另外一种加密方式//防止用户恶意篡改
  clearInvalidConfig: true, // 发生 SyntaxError  则清空配置,
  accessPropertiesByDotNotation: true, //通过点符号访问嵌套属性 ，默认着为true
}

const store = new Store(option)
ipcMain.on('setStore', (_, key, value) => {
  store.set(key, value)
})

ipcMain.on('getAllStore', (_) => {
  const value = store.store
  _.returnValue = value || ''
})

ipcMain.on('getStore', (_, key) => {
  const value = store.get(key)
  _.returnValue = value || ''
})

ipcMain.on('removeStore', (_, key) => {
  store.delete(key)
})

ipcMain.on('clearStore', () => {
  store.clear()
})
// 获取窗口的webContents对象

store.onDidAnyChange((newValue, oldValue) => {
  win.webContents.send('storeChange', newValue, oldValue)
  // 这里可以执行你想要的逻辑
})

/**file*/
// 设置存放缓存文件的文件夹
const TMPPATH = 'temp'
const TMPNAME = 'temp_name'
// 设置文件夹位置（在安装应用文件夹内）
const basePath = path.join(configPath, TMPPATH)
fs.mkdir(basePath, { recursive: true }, (err) => {
  if (err) console.log(`mkdir path: ${basePath} err`)
})

ipcMain.on('addFile', (_, arrayBuffer, fileName) => {
  try {
    const buffer = Buffer.from(arrayBuffer)
    const name = TMPNAME + fileName
    const fullPath = path.join(basePath, name)
    fs.writeFileSync(fullPath, buffer)
    const stats = fs.statSync(fullPath)
    const fileType = path.extname(fullPath).substring(1)
    _.returnValue = { path: fullPath, name: name, size: stats.size, fileType }
  } catch (error) {
    _.returnValue = ''
  }
})

ipcMain.on('chooseFiles', (_, fileTypes) => {
  let targetFolders: any[] = Array.from([])
  let allSuccess = true
  console.log(fileTypes)
  dialog
    .showOpenDialog(win, {
      properties: ['openFile', 'multiSelections'],
      filters: [{ name: 'Images', extensions: fileTypes }],
    })
    .then((result) => {
      const { filePaths, canceled } = result
      if (canceled) {
        _.returnValue = []
      }
      filePaths.forEach((file) => {
        const fileName = path.basename(file)
        const currentDate = dayjs().unix()
        const targetFolder = path.join(basePath, TMPNAME + currentDate + fileName)
        fs.copyFile(file, targetFolder, (err) => {
          if (err) {
            // 文件复制失败
            console.error(`文件复制失败: ${file}`, err)
            allSuccess = false
          } else {
            // 文件复制成功
            console.log(`文件复制成功: ${file}`)
            const stats = fs.statSync(targetFolder)
            const fileType = path.extname(targetFolder).substring(1)
            targetFolders = [
              ...targetFolders,
              { path: targetFolder, name: fileName, size: stats.size, fileType },
            ]
          }

          // 判断是否所有文件都已处理完成
          if (targetFolders.length === filePaths.length) {
            if (allSuccess) {
              _.returnValue = targetFolders
            } else {
              _.returnValue = targetFolders
              console.error('文件复制失败-不完整')
            }
          }
        })
      })
    })
    .catch((err) => {
      console.log(err)
    })
})

ipcMain.on('readFiles', (_, pathName) => {
  if (fs.existsSync(pathName)) {
    fs.readFile(pathName, (err, data) => {
      if (err) {
        console.log(`文件读取-失败: ${pathName}`)
        _.returnValue = ''
      }
      console.log(`文件已读取: ${pathName}`)
      const fileName = path.basename(pathName)
      const fileType = path.extname(pathName).substring(1)
      _.returnValue = { fileName, fileType, data }
    })
  } else {
    console.log(`文件读取-不存在: ${pathName}`)
    _.returnValue = ''
  }
})

ipcMain.on('removeFiles', (_, filePath) => {
  if (fs.existsSync(filePath)) {
    fs.unlinkSync(filePath)
    console.log(`文件已删除: ${filePath}`)
  } else {
    console.log(`文件删除-不存在: ${filePath}`)
  }
})
//判断权限
ipcMain.handle('permissions', async (_, mediaType: 'camera' | 'microphone') => {
  const res = systemPreferences.getMediaAccessStatus(mediaType)
  if (res != 'granted') {
    return false
  }
  return true
})

//打开设置
ipcMain.on('openSetting', async (_, mediaType: 'camera' | 'microphone') => {
  const curtOS = (await si.osInfo()).distro == 'macOS' ? 'macOS' : 'Windows' // 比如是Mac
  const platformCommandMap = {
    Windows: {
      camera: `start ms-settings:privacy-webcam`,
      microphone: `start ms-settings:privacy-microphone`,
    },
    macOS: {
      camera: `open x-apple.systempreferences:com.apple.preference.security\?Privacy_Camera`,
      microphone: `open x-apple.systempreferences:com.apple.preference.security\?Privacy_Microphone`,
    },
  }
  const command = platformCommandMap[curtOS][mediaType] || ''
  command && exec(command)
})

// 获取系统信息
// ipcMain.handle('serialNumber', async () => {
//   const data = await si.chassis()
//   console.log(data.serial)
//   return data[0].serialNum
// })

// 获取系统信息
ipcMain.handle('serialNumber', async () => {
  const curtOS = (await si.osInfo()).distro == 'macOS' ? 'macOS' : 'Windows' // 比如是Mac
  try {
    let result
    // 获取 Windows 系统序列号
    if (curtOS == 'macOS') {
      result = await getSerialNumberMacOs()
    } else {
      result = await getSerialNumber()
    }
    console.log('Windows 系统序列号:', result)
    return result
  } catch (error) {
    console.error('获取 Windows 系统序列号失败:', error)
    return null
  }
})

function getSerialNumber() {
  return new Promise((resolve, reject) => {
    exec('wmic bios get serialnumber', { encoding: 'utf8' }, (error, stdout, stderr) => {
      if (error) {
        console.error('执行命令时出错: ', error)
        resolve(null)
      }
      if (stderr) {
        console.error('执行命令时出错: ', error)
        resolve(null)
      }
      console.log('BIOS 序列号: ', stdout.replace('SerialNumber', '').trim())
      resolve(stdout.replace('SerialNumber', '').trim())
    })
  })
}

function getSerialNumberMacOs() {
  return new Promise((resolve, reject) => {
    si.chassis()
      .then((data) => {
        resolve(data.serial.trim())
      })
      .catch((err) => {
        reject(err)
      })
  })
}

ipcMain.handle('ping', async (_, hostname) => {
  //采用qiao-is-online判断当前网络
  return new Promise((resolve) => {
    ping(hostname).then((res) => {
      resolve(res.alive)
    })
  })
  //网络没有链接上则继续保持在网络异常界面
  // const curtOS = (await si.osInfo()).distro == 'macOS' ? 'macOS' : 'Windows' // 比如是Mac
  // const platformCommandMap = {
  //   Windows: {
  //     ping: `ping -n 1 -w 1000  ${hostname}`,
  //   },
  //   macOS: {
  //     ping: `ping -c 1 -W 1  ${hostname}`,
  //   },
  // }
  // return new Promise((resolve) => {
  //   exec(platformCommandMap[curtOS].ping, { encoding: 'utf8' }, (error, stdout, stderr) => {
  //     if (error) {
  //       resolve(false)
  //     }
  //     if (stderr) {
  //       resolve(false)
  //     }
  //     resolve(true)
  //   })
  // })
})
